/*
 *   Licensed to the Apache Software Foundation (ASF) under one
 *   or more contributor license agreements.  See the NOTICE file
 *   distributed with this work for additional information
 *   regarding copyright ownership.  The ASF licenses this file
 *   to you under the Apache License, Version 2.0 (the
 *   "License"); you may not use this file except in compliance
 *   with the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 *   Unless required by applicable law or agreed to in writing,
 *   software distributed under the License is distributed on an
 *   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 *   KIND, either express or implied.  See the License for the
 *   specific language governing permissions and limitations
 *   under the License.
 *
 */

package org.apache.directory.studio.proxy;


import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;

import org.apache.directory.ldap.client.api.message.LdapResult;
import org.apache.directory.shared.ldap.codec.LdapConstants; //import org.apache.directory.shared.ldap.entry.DefaultEntry;
//import org.apache.directory.shared.ldap.entry.DefaultEntryAttribute;
import org.apache.directory.shared.ldap.entry.DefaultServerEntry;
import org.apache.directory.shared.ldap.entry.Entry;
import org.apache.directory.shared.ldap.entry.EntryAttribute;
import org.apache.directory.shared.ldap.entry.Modification;
import org.apache.directory.shared.ldap.entry.Value;
import org.apache.directory.shared.ldap.exception.LdapInvalidDnException;
import org.apache.directory.shared.ldap.filter.SearchScope;
import org.apache.directory.shared.ldap.message.AbandonRequestImpl;
import org.apache.directory.shared.ldap.message.AddRequestImpl;
import org.apache.directory.shared.ldap.message.AddResponseImpl;
import org.apache.directory.shared.ldap.message.AliasDerefMode;
import org.apache.directory.shared.ldap.message.BindRequestImpl;
import org.apache.directory.shared.ldap.message.BindResponseImpl;
import org.apache.directory.shared.ldap.message.CompareRequestImpl;
import org.apache.directory.shared.ldap.message.CompareResponseImpl;
import org.apache.directory.shared.ldap.message.DeleteRequestImpl;
import org.apache.directory.shared.ldap.message.DeleteResponseImpl;
import org.apache.directory.shared.ldap.message.ExtendedRequestImpl;
import org.apache.directory.shared.ldap.message.ExtendedResponseImpl;
import org.apache.directory.shared.ldap.message.ModifyDnRequestImpl;
import org.apache.directory.shared.ldap.message.ModifyDnResponseImpl;
import org.apache.directory.shared.ldap.message.ModifyRequestImpl;
import org.apache.directory.shared.ldap.message.ModifyResponseImpl;
import org.apache.directory.shared.ldap.message.ReferralImpl;
import org.apache.directory.shared.ldap.message.ResultCodeEnum;
import org.apache.directory.shared.ldap.message.SearchRequestImpl;
import org.apache.directory.shared.ldap.message.SearchResponseDoneImpl;
import org.apache.directory.shared.ldap.message.SearchResponseEntryImpl;
import org.apache.directory.shared.ldap.message.SearchResponseReferenceImpl;
import org.apache.directory.shared.ldap.message.UnbindRequestImpl;
import org.apache.directory.shared.ldap.message.internal.InternalAbandonRequest;
import org.apache.directory.shared.ldap.message.internal.InternalAddRequest;
import org.apache.directory.shared.ldap.message.internal.InternalAddResponse;
import org.apache.directory.shared.ldap.message.internal.InternalBindRequest;
import org.apache.directory.shared.ldap.message.internal.InternalBindResponse;
import org.apache.directory.shared.ldap.message.internal.InternalCompareRequest;
import org.apache.directory.shared.ldap.message.internal.InternalCompareResponse;
import org.apache.directory.shared.ldap.message.internal.InternalDeleteRequest;
import org.apache.directory.shared.ldap.message.internal.InternalDeleteResponse;
import org.apache.directory.shared.ldap.message.internal.InternalExtendedRequest;
import org.apache.directory.shared.ldap.message.internal.InternalExtendedResponse;
import org.apache.directory.shared.ldap.message.internal.InternalLdapResult;
import org.apache.directory.shared.ldap.message.internal.InternalModifyDnRequest;
import org.apache.directory.shared.ldap.message.internal.InternalModifyDnResponse;
import org.apache.directory.shared.ldap.message.internal.InternalModifyRequest;
import org.apache.directory.shared.ldap.message.internal.InternalModifyResponse;
import org.apache.directory.shared.ldap.message.internal.InternalReferral;
import org.apache.directory.shared.ldap.message.internal.InternalSearchRequest;
import org.apache.directory.shared.ldap.message.internal.InternalSearchResponseDone;
import org.apache.directory.shared.ldap.message.internal.InternalSearchResponseEntry;
import org.apache.directory.shared.ldap.message.internal.InternalSearchResponseReference;
import org.apache.directory.shared.ldap.message.internal.InternalUnbindRequest;
import org.apache.directory.shared.ldap.name.DN;
import org.apache.directory.shared.ldap.name.RDN;
import org.apache.mina.core.session.IoSession;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.dom4j.Node;
import org.dom4j.io.OutputFormat;
import org.dom4j.io.SAXReader;
import org.dom4j.io.XMLWriter;


/**
 * Reading, Writing of LDAP messages to and from XML log files are done here.
 *
 * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
 * @version $Rev$, $Date$
 */
public class ProxyIO
{
    //Authentication types
    private static final String TYPE_SASL = "SASL";
    private static final String TYPE_SIMPLE = "simple";

    //Deref Aliases
    private static final String DEREF_ALWAYS_CONST = "deref Always";
    private static final String DEREF_FINDING_BASE_OBJ_CONST = "deref Finding Base Obj";
    private static final String DEREF_IN_SEARCHING_CONST = "deref In Searching";
    private static final String NEVER_DEREF_ALIASES_CONST = "never Deref Aliases";

    // XML tags
    private static final String TYPE_TAG = "type";
    private static final String RESPONSE_TAG = "response";
    private static final String RESPONSE_NAME_TAG = "responseName";
    private static final String EXTENDED_RESPONSE_TAG = "extendedResponse";
    private static final String MODIFY_DN_RESPONSE_TAG = "modifyDnResponse";
    private static final String MODIFY_RESPONSE_TAG = "modifyResponse";
    private static final String COMPARE_RESPONSE_TAG = "compareResponse";
    private static final String DELETE_RESPONSE_TAG = "deleteResponse";
    private static final String SEARCH_RESPONSE_REFERENCE_TAG = "searchResponseReference";
    private static final String OBJECT_NAME_TAG = "objectName";
    private static final String SEARCH_RESPONSE_ENTRY_TAG = "searchResponseEntry";
    private static final String SEARCH_RESPONSE_DONE_TAG = "searchResponseDone";
    private static final String SERVER_SASL_CREDS_TAG = "serverSaslCreds";
    private static final String BIND_RESPONSE_TAG = "bindResponse";
    private static final String REFERRAL_TAG = "referral";
    private static final String ERROR_MESSAGE_TAG = "errorMessage";
    private static final String MATCHED_DN_TAG = "matchedDn";
    private static final String RESULT_CODE_TAG = "resultCode";
    private static final String LDAP_RESULT_TAG = "LDAPResult";
    private static final String ADD_RESPONSE_TAG = "addResponse";
    private static final String PAYLOAD_TAG = "payload";
    private static final String OID_TAG = "oid";
    private static final String EXTENDED_REQUEST_TAG = "extendedRequest";
    private static final String NEW_SUPERIOR_TAG = "newSuperior";
    private static final String DELETE_OLD_RDN_TAG = "deleteOldRdn";
    private static final String NEW_RDN_TAG = "newRdn";
    private static final String MODIFY_DN_REQUEST_TAG = "modifyDnRequest";
    private static final String OPERATION_TAG = "operation";
    private static final String MODIFICATION_TAG = "modification";
    private static final String MODIFICATION_ITEMS_TAG = "modificationItems";
    private static final String MODIFY_REQUEST_TAG = "modifyRequest";
    private static final String ASSERTION_VALUE_TAG = "assertionValue";
    private static final String ATTRIBUTE_ID_TAG = "attributeID";
    private static final String COMPARE_REQUEST_TAG = "compareRequest";
    private static final String ABANDONED_TAG = "abandoned";
    private static final String ABANDON_REQUEST_TAG = "abandonRequest";
    private static final String DELETE_REQUEST_TAG = "deleteRequest";
    private static final String ENTRY_TAG = "entry";
    private static final String ENTRY_DN_TAG = "entryDn";
    private static final String ADD_REQUEST_TAG = "addRequest";
    private static final String UNBIND_REQUEST_TAG = "unbindRequest";
    private static final String MECHANISM_TAG = "mechanism";
    private static final String CREDENTIALS_TAG = "credentials";
    private static final String AUTHENTICATION_TAG = "authentication";
    private static final String NAME_TAG = "name";
    private static final String VERSION_TAG = "version";
    private static final String BIND_REQUEST_TAG = "bindRequest";
    private static final String ATTRIBUTE_TAG = "attribute";
    private static final String ATTRIBUTES_TAG = "attributes";
    private static final String ALIAS_DEREF_MODE_TAG = "aliasDerefMode";
    private static final String TIME_LIMIT_TAG = "timeLimit";
    private static final String SIZE_LIMIT_TAG = "sizeLimit";
    private static final String TYPES_ONLY_TAG = "typesOnly";
    private static final String SCOPE_TAG = "scope";
    private static final String FILTER_TAG = "filter";
    private static final String BASE_DN_TAG = "baseDn";
    private static final String MESSAGE_ID_TAG = "messageID";
    private static final String SEARCH_REQUEST_TAG = "searchRequest"; //$NON-NLS-1$
    private static final String UP_ID_TAG = "upID";
    private static final String VALUE_TAG = "value";
    private static final String IS_BINARY_TAG = "isBinary";
    private static final String LDAP_URL_TAG = "LDAPurl";
    private static final String ASSERTION_TAG = "assertion";
    private static final String IS_REFERRAL_TAG = "isReferral";


    /**
     * Writes Search Request to the log file
     *
     * @param message InternalSearch Request to be written to the file
     * @param document The XML document for the message to be written to
     * @param session The session corresponding to this conversation
     * @throws IOException
     */

    public static void writeSearchRequest( InternalSearchRequest message, Document document, IoSession session )
        throws IOException
    {
        // Creating the Document        
        Element documentRoot = document.getRootElement();
        // Creating the root element
        Element root = documentRoot.addElement( ProxyIO.SEARCH_REQUEST_TAG );

        //getting the MessageID
        root.addAttribute( ProxyIO.MESSAGE_ID_TAG, Integer.toString( message.getMessageId() ) );

        //getting the BaseDn
        if ( message.getBase() != null )
        {
            root.addAttribute( ProxyIO.BASE_DN_TAG, message.getBase().getName() );
        }
        //Getting the Filter
        Element filterElement = root.addElement( ProxyIO.FILTER_TAG );
        filterElement.setText( message.getFilter().toString() );
        // TODO Set filter properly
        //Getting the scope
        String sc = "null";
        switch ( message.getScope() )
        {
            case OBJECT:
                sc = "base object";
                break;

            case ONELEVEL:
                sc = "single level";
                break;

            case SUBTREE:
                sc = "whole subtree";
                break;
        }
        root.addAttribute( ProxyIO.SCOPE_TAG, sc );

        //Getting the TypesOnly
        root.addAttribute( ProxyIO.TYPES_ONLY_TAG, message.getTypesOnly() ? "true" : "false" );

        //Getting the size limit
        root.addAttribute( ProxyIO.SIZE_LIMIT_TAG, Long.toString( message.getSizeLimit() ) );

        //Getting the time limit
        root.addAttribute( ProxyIO.TIME_LIMIT_TAG, Long.toString( message.getTimeLimit() ) );

        //Getting the AliasDerefMode         
        String deref = "null";
        switch ( message.getDerefAliases().getValue() )
        {
            case LdapConstants.NEVER_DEREF_ALIASES:
                deref = ProxyIO.NEVER_DEREF_ALIASES_CONST;
                break;

            case LdapConstants.DEREF_IN_SEARCHING:
                deref = ProxyIO.DEREF_IN_SEARCHING_CONST;
                break;

            case LdapConstants.DEREF_FINDING_BASE_OBJ:
                deref = ProxyIO.DEREF_FINDING_BASE_OBJ_CONST;
                break;

            case LdapConstants.DEREF_ALWAYS:
                deref = ProxyIO.DEREF_ALWAYS_CONST;
                break;
        }
        root.addAttribute( ProxyIO.ALIAS_DEREF_MODE_TAG, deref );

        //Getting the attributes
        Element attributesElement = root.addElement( ProxyIO.ATTRIBUTES_TAG );
        List<String> attributes = message.getAttributes();

        for ( String attr : attributes )
        {
            Element attributeElement = attributesElement.addElement( ProxyIO.ATTRIBUTE_TAG );
            attributeElement.addAttribute( ProxyIO.NAME_TAG, attr );
        }

        writeToDisk( session, document );
    }


    /**
     * Writes Bind Request to the log file
     *
     * @param message InternalBind Request to be written to the file
     * @param document The XML document for the message to be written to
     * @param session The session corresponding to this conversation
     * @throws IOException
     */

    public static void writeBindRequest( InternalBindRequest message, Document document, IoSession session )

    {
        // Creating the Document        
        Element documentRoot = document.getRootElement();
        // Creating the root element
        Element root = documentRoot.addElement( ProxyIO.BIND_REQUEST_TAG );

        //getting the MessageID
        root.addAttribute( ProxyIO.MESSAGE_ID_TAG, Integer.toString( message.getMessageId() ) );

        //Getting the version
        Element versionElement = root.addElement( ProxyIO.VERSION_TAG );
        versionElement.setText( message.isVersion3() ? "3" : "2" );

        //Getting the name
        Element nameElement = root.addElement( ProxyIO.NAME_TAG );
        if ( message.getName() != null )
        {
            nameElement.setText( message.getName().toString() );
        }
        //Getting the authentication type, mechanism and credentials
        Element authElement = root.addElement( ProxyIO.AUTHENTICATION_TAG );

        if ( message.isSimple() )
        {
            authElement.addAttribute( ProxyIO.TYPE_TAG, ProxyIO.TYPE_SIMPLE );
        }
        else
        {
            authElement.addAttribute( ProxyIO.TYPE_TAG, ProxyIO.TYPE_SASL );
            Element mechanismElement = authElement.addElement( ProxyIO.MECHANISM_TAG );
            mechanismElement.setText( message.getSaslMechanism() );
        }
        Element credentialsElement = authElement.addElement( ProxyIO.CREDENTIALS_TAG );
        credentialsElement.setText( new String( message.getCredentials() ) );

        writeToDisk( session, document );
    }


    /**
     * Writing the document to a file
     *
     * @param document to be written to
     * @param session for the respective message
     */
    public static void writeToDisk( IoSession session, Document document )
    {
        // Writing the file to disk
        try
        {
            OutputFormat outformat = OutputFormat.createPrettyPrint();
            outformat.setEncoding( "UTF-8" ); //$NON-NLS-1$
            System.out.println( session.getId() + "" );
            BufferedWriter out = new BufferedWriter( new FileWriter( new File( "log" + session.getId() ), true ) );
            XMLWriter writer = new XMLWriter( out, outformat );
            writer.write( document );

            writer.flush();
        }
        catch ( Throwable e )
        {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }


    /**
     * Writes Unbind Request to the log file
     *
     * @param message InternalUnbind Request to be written to the file
     * @param document The XML document for the message to be written to
     * @param session The session corresponding to this conversation
     * @throws IOException
     */

    public static void writeUnbindRequest( InternalUnbindRequest message, Document document, IoSession session )
        throws IOException
    {
        // Creating the Document        
        Element documentRoot = document.getRootElement();

        // Creating the root element
        Element root = documentRoot.addElement( ProxyIO.UNBIND_REQUEST_TAG );

        //getting the MessageID
        root.addAttribute( ProxyIO.MESSAGE_ID_TAG, Integer.toString( message.getMessageId() ) );

        //writeToDisk( document );
        ProxyIO.writeToDisk( session, document );

    }


    /**
     * Writes Add Request to the log file
     *
     * @param message InternalAdd Request to be written to the file
     * @param document The XML document for the message to be written to
     * @param session The session corresponding to this conversation
     * @throws IOException
     */
    public static void writeAddRequest( InternalAddRequest message, Document document, IoSession session )
        throws IOException
    {
        // Creating the Document
        Element documentRoot = document.getRootElement();
        // Creating the root element
        Element root = documentRoot.addElement( ProxyIO.ADD_REQUEST_TAG );

        //getting the MessageID
        root.addAttribute( ProxyIO.MESSAGE_ID_TAG, Integer.toString( message.getMessageId() ) );

        //Getting the entryDN
        if ( message.getEntryDn() != null )
        {
            root.addAttribute( ProxyIO.ENTRY_DN_TAG, message.getEntryDn().getName() );
        }
        //Getting attributes
        for ( Iterator<EntryAttribute> it = message.getEntry().iterator(); it.hasNext(); )
        {
            EntryAttribute s = it.next();
            //Getting the entryAttributes
            Element attributeElement = root.addElement( ProxyIO.ATTRIBUTE_TAG );
            attributeElement.addAttribute( ProxyIO.UP_ID_TAG, s.getId() );
            for ( Iterator<Value<?>> values = s.getAll(); values.hasNext(); )
            {
                Value val = values.next();
                Element valueElement = attributeElement.addElement( ProxyIO.VALUE_TAG );
                if ( !val.isBinary() )
                {
                    valueElement.addAttribute( ProxyIO.IS_BINARY_TAG, "false" );
                    valueElement.setText( val.getString() );
                }
                else
                {
                    valueElement.addAttribute( ProxyIO.IS_BINARY_TAG, "true" );
                    String value = new String( val.getBytes() );
                    valueElement.setText( value );
                }
            }

        }

        writeToDisk( session, document );

    }


    /**
     * Writes Delete Request to the log file
     *
     * @param message InternalDelete Request to be written to the file
     * @param document The XML document for the message to be written to
     * @param session The session corresponding to this conversation
     * @throws IOException
     */
    public static void writeDeleteRequest( InternalDeleteRequest message, Document document, IoSession session )
        throws IOException
    {
        // Creating the Document
        Element documentRoot = document.getRootElement();
        // Creating the root element
        Element root = documentRoot.addElement( ProxyIO.DELETE_REQUEST_TAG );

        //getting the MessageID
        root.addAttribute( ProxyIO.MESSAGE_ID_TAG, Integer.toString( message.getMessageId() ) );

        //Getting the name
        if ( message.getName() != null )
        {
            root.addAttribute( ProxyIO.NAME_TAG, message.getName().getName() );
        }
        writeToDisk( session, document );

    }


    /**
     * Writes Abandon Request to the log file
     *
     * @param message InternalAbandon Request to be written to the file
     * @param document The XML document for the message to be written to
     * @param session The session corresponding to this conversation
     * @throws IOException
     */
    public static void writeAbandonRequest( InternalAbandonRequest message, Document document, IoSession session )
        throws IOException
    {
        // Creating the Document
        Element documentRoot = document.getRootElement();
        // Creating the root element
        Element root = documentRoot.addElement( ProxyIO.ABANDON_REQUEST_TAG );

        //getting the MessageID        
        root.addAttribute( ProxyIO.MESSAGE_ID_TAG, Integer.toString( message.getMessageId() ) );

        //Getting the abandoned
        Element abandonedElement = root.addElement( ProxyIO.ABANDONED_TAG );
        abandonedElement.setText( Integer.toString( message.getAbandoned() ) );

        writeToDisk( session, document );

    }


    /**
     * Writes Compare Request to the log file
     *
     * @param message InternalCompare Request to be written to the file
     * @param document The XML document for the message to be written to
     * @param session The session corresponding to this conversation
     * @throws IOException
     */
    public static void writeCompareRequest( InternalCompareRequest message, Document document, IoSession session )
        throws IOException
    {
        // Creating the Document       
        Element documentRoot = document.getRootElement();
        // Creating the root element
        Element root = documentRoot.addElement( ProxyIO.COMPARE_REQUEST_TAG );

        //getting the MessageID
        root.addAttribute( ProxyIO.MESSAGE_ID_TAG, Integer.toString( message.getMessageId() ) );

        //Getting the name
        if ( message.getName() != null )
        {
            root.addAttribute( ProxyIO.NAME_TAG, message.getName().getName() );
        }
        //Getting the attributeID
        Element assertionElement = root.addElement( ProxyIO.ASSERTION_TAG );
        assertionElement.addAttribute( ProxyIO.ATTRIBUTE_ID_TAG, message.getAttributeId() );

        //Getting the Assertion value
        Element assertionValueElement = assertionElement.addElement( ProxyIO.VALUE_TAG );
        Value val = message.getAssertionValue();
        if ( !val.isBinary() )
        {
            assertionValueElement.addAttribute( ProxyIO.IS_BINARY_TAG, "false" );
            assertionValueElement.setText( val.getString() );
        }
        else
        {
            assertionValueElement.addAttribute( ProxyIO.IS_BINARY_TAG, "true" );
            String value = new String( val.getBytes() );
            assertionValueElement.setText( value );
        }

        writeToDisk( session, document );
    }


    /**
     * Writes Modify Request to the log file
     *
     * @param message InternalModify Request to be written to the file
     * @param document The XML document for the message to be written to
     * @param session The session corresponding to this conversation
     * @throws IOException
     */
    public static void writeModifyRequest( InternalModifyRequest message, Document document, IoSession session )
        throws IOException
    {
        // Creating the Document
        Element documentRoot = document.getRootElement();
        // Creating the root element
        Element root = documentRoot.addElement( ProxyIO.MODIFY_REQUEST_TAG );

        //getting the MessageID
        root.addAttribute( ProxyIO.MESSAGE_ID_TAG, Integer.toString( message.getMessageId() ) );

        //Getting the name
        if ( message.getName() != null )
        {
            root.addAttribute( ProxyIO.NAME_TAG, message.getName().getName() );
        }
        //Getting the modificationItems

        Collection<Modification> modificationItems = message.getModificationItems();

        for ( Modification item : modificationItems )
        {
            Element modElement = root.addElement( ProxyIO.MODIFICATION_TAG );

            String op = "null";
            switch ( item.getOperation().getValue() )
            {
                case LdapConstants.OPERATION_ADD:
                    op = "add";
                    break;

                case LdapConstants.OPERATION_DELETE:
                    op = "delete";
                    break;

                case LdapConstants.OPERATION_REPLACE:
                    op = "replace";
                    break;

            }
            modElement.addAttribute( ProxyIO.OPERATION_TAG, op );

            modElement.addAttribute( ProxyIO.UP_ID_TAG, item.getAttribute().getUpId() );
            for ( Iterator<Value<?>> values = item.getAttribute().getAll(); values.hasNext(); )
            {
                Value val = values.next();
                Element valueElement = modElement.addElement( ProxyIO.VALUE_TAG );
                if ( !val.isBinary() )
                {
                    valueElement.addAttribute( ProxyIO.IS_BINARY_TAG, "false" );
                    valueElement.setText( val.getString() );
                }
                else
                {
                    valueElement.addAttribute( ProxyIO.IS_BINARY_TAG, "true" );
                    String value = new String( val.getBytes() );
                    valueElement.setText( value );
                }
            }
        }

        writeToDisk( session, document );

    }


    /**
     * Writes ModifyDn Request to the log file
     *
     * @param message InternalModifyDn Request to be written to the file
     * @param document The XML document for the message to be written to
     * @param session The session corresponding to this conversation
     * @throws IOException
     */
    public static void writeModifyDnRequest( InternalModifyDnRequest message, Document document, IoSession session )
        throws IOException
    {
        // Creating the Document
        Element documentRoot = document.getRootElement();
        // Creating the root element
        Element root = documentRoot.addElement( ProxyIO.MODIFY_DN_REQUEST_TAG );

        //getting the MessageID
        root.addAttribute( ProxyIO.MESSAGE_ID_TAG, Integer.toString( message.getMessageId() ) );

        //Getting the name
        if ( message.getName() != null )
        {
            root.addAttribute( ProxyIO.NAME_TAG, message.getName().getName() );
        }
        //Getting the new RDN
        if ( message.getNewRdn() != null )
        {
            root.addAttribute( ProxyIO.NEW_RDN_TAG, message.getNewRdn().getName() );
        }
        //Getting the delete Old Rdn
        root.addAttribute( ProxyIO.DELETE_OLD_RDN_TAG, message.getDeleteOldRdn() ? "true" : "false" );

        //Getting the new superior
        if ( message.getNewSuperior() != null )
        {
            root.addAttribute( ProxyIO.NEW_SUPERIOR_TAG, message.getNewSuperior().getName() );
        }
        writeToDisk( session, document );

    }


    /**
     * Writes Extended Request to the log file
     *
     * @param message InternalExtended Request to be written to the file
     * @param document The XML document for the message to be written to
     * @param session The session corresponding to this conversation
     * @throws IOException
     */
    public static void writeExtendedRequest( InternalExtendedRequest message, Document document, IoSession session )
        throws IOException
    {
        // Creating the Document
        Element documentRoot = document.getRootElement();
        // Creating the root element
        Element root = documentRoot.addElement( ProxyIO.EXTENDED_REQUEST_TAG );

        //getting the MessageID
        root.addAttribute( ProxyIO.MESSAGE_ID_TAG, Integer.toString( message.getMessageId() ) );

        //Getting the Oid
        Element oidElement = root.addElement( ProxyIO.OID_TAG );
        oidElement.setText( message.getOid() );

        //Getting the Payload
        Element payloadElement = root.addElement( ProxyIO.PAYLOAD_TAG );
        payloadElement.setText( new String( message.getPayload() ) );

        writeToDisk( session, document );

    }


    /**
     * Writes Add Response to the log file
     *
     * @param response InternalAddResponse to be written to the file
     * @param document The XML document for the response to be written to
     * @param session The session corresponding to this conversation
     * @throws IOException
     */
    public static void writeAddResponse( InternalAddResponse response, Document document, IoSession session )
        throws IOException
    {
        // Creating the Document
        Element documentRoot = document.getRootElement();
        // Creating the root element
        Element root = documentRoot.addElement( ProxyIO.ADD_RESPONSE_TAG );

        //getting the MessageID
        root.addAttribute( ProxyIO.MESSAGE_ID_TAG, Integer.toString( response.getMessageId() ) );

        //Writing the LDAP result part
        writeLDAPResult( root, response.getLdapResult() );

        writeToDisk( session, document );

    }


    /**
     * Writes LDAPResult part in a message to a log file
     *
     * @param ldapResult LDAP Result part of the message to be written to the file
     * @param root Root element of the document to be written
     * @param session The session corresponding to this conversation
     * @throws IOException
     */
    private static void writeLDAPResult( Element root, InternalLdapResult ldapResult )
    {
        Element LDAPResultElement = root.addElement( ProxyIO.LDAP_RESULT_TAG );

        //Getting the Result Code
        Element ResultCodeElement = LDAPResultElement.addElement( ProxyIO.RESULT_CODE_TAG );
        ResultCodeElement.setText( Integer.toString( ldapResult.getResultCode().getResultCode() ) );

        //Getting the Matched Dn
        Element MatchedDnElement = LDAPResultElement.addElement( ProxyIO.MATCHED_DN_TAG );
        if ( ldapResult.getMatchedDn() != null )
        {
            MatchedDnElement.setText( ldapResult.getMatchedDn().getName() );
        }

        //Getting the Error Msg
        Element ErrorMsgElement = LDAPResultElement.addElement( ProxyIO.ERROR_MESSAGE_TAG );
        if ( ldapResult.getErrorMessage() != null )
        {
            ErrorMsgElement.setText( ldapResult.getErrorMessage() );
        }

        //Getting the Referral
        if ( ldapResult.isReferral() )
        {
            LDAPResultElement.addAttribute( ProxyIO.IS_REFERRAL_TAG, "true" );
            Element ReferralElement = LDAPResultElement.addElement( ProxyIO.REFERRAL_TAG );
            Collection<String> ldapUrls = ldapResult.getReferral().getLdapUrls();
            for ( String url : ldapUrls )
            {
                Element LDAPUrlElement = ReferralElement.addElement( ProxyIO.LDAP_URL_TAG );
                LDAPUrlElement.setText( url );
            }
        }
        else
        {
            LDAPResultElement.addAttribute( ProxyIO.IS_REFERRAL_TAG, "false" );
        }

    }


    /**
     * Writes Bind Response to the log file
     *
     * @param response InternalBindResponse to be written to the file
     * @param document The XML document for the response to be written to
     * @param session The session corresponding to this conversation
     * @throws IOException
     */
    public static void writeBindResponse( InternalBindResponse response, Document document, IoSession session )
        throws IOException
    {
        // Creating the Document
        Element documentRoot = document.getRootElement();
        // Creating the root element
        Element root = documentRoot.addElement( ProxyIO.BIND_RESPONSE_TAG );

        //getting the MessageID
        root.addAttribute( ProxyIO.MESSAGE_ID_TAG, Integer.toString( response.getMessageId() ) );

        //Getting Server SASL credentials
        Element ServerSaslCredsElement = root.addElement( ProxyIO.SERVER_SASL_CREDS_TAG );
        if ( response.getServerSaslCreds() != null )
        {
            ServerSaslCredsElement.setText( new String( response.getServerSaslCreds() ) );
        }
        //Writing the LDAP result part
        writeLDAPResult( root, response.getLdapResult() );

        writeToDisk( session, document );

    }


    /**
     * Writes SearchResponseDone to the log file
     *
     * @param response InternalSearchResponseDone to be written to the file
     * @param document The XML document for the response to be written to
     * @param session The session corresponding to this conversation
     * @throws IOException
     */
    public static void writeSearchResponseDone( InternalSearchResponseDone response, Document document,
        IoSession session ) throws IOException
    {
        // Creating the Document
        Element documentRoot = document.getRootElement();
        // Creating the root element
        Element root = documentRoot.addElement( ProxyIO.SEARCH_RESPONSE_DONE_TAG );

        //getting the MessageID
        root.addAttribute( ProxyIO.MESSAGE_ID_TAG, Integer.toString( response.getMessageId() ) );

        //Writing the LDAP result part
        writeLDAPResult( root, response.getLdapResult() );

        writeToDisk( session, document );

    }


    /**
     * Writes SearchResponseEntry to the log file
     *
     * @param response InternalSearchResponseEntry to be written to the file
     * @param document The XML document for the response to be written to
     * @param session The session corresponding to this conversation
     * @throws IOException
     */
    public static void writeSearchResponseEntry( InternalSearchResponseEntry response, Document document,
        IoSession session ) throws IOException
    {
        // Creating the Document
        Element documentRoot = document.getRootElement();
        // Creating the root element
        Element root = documentRoot.addElement( ProxyIO.SEARCH_RESPONSE_ENTRY_TAG );

        //getting the MessageID
        root.addAttribute( ProxyIO.MESSAGE_ID_TAG, Integer.toString( response.getMessageId() ) );

        //Getting Object name
        root.addAttribute( ProxyIO.OBJECT_NAME_TAG, response.getObjectName().getName() );

        //Getting attributes
        for ( Iterator<EntryAttribute> it = response.getEntry().iterator(); it.hasNext(); )
        {
            EntryAttribute s = it.next();
            //Getting the entryAttributes
            Element attributeElement = root.addElement( ProxyIO.ATTRIBUTE_TAG );
            attributeElement.addAttribute( ProxyIO.UP_ID_TAG, s.getId() );
            for ( Iterator<Value<?>> values = s.getAll(); values.hasNext(); )
            {
                Value val = values.next();
                Element valueElement = attributeElement.addElement( ProxyIO.VALUE_TAG );
                if ( !val.isBinary() )
                {
                    valueElement.addAttribute( ProxyIO.IS_BINARY_TAG, "false" );
                    valueElement.setText( val.getString() );
                }
                else
                {
                    valueElement.addAttribute( ProxyIO.IS_BINARY_TAG, "true" );
                    String value = new String( val.getBytes() );
                    valueElement.setText( value );
                }
            }

        }

        writeToDisk( session, document );

    }


    /**
     * Writes SearchResponseReference to the log file
     *
     * @param response InternalSearchResponseReference to be written to the file
     * @param document The XML document for the response to be written to
     * @param session The session corresponding to this conversation
     * @throws IOException
     */
    public static void writeSearchResponseReference( InternalSearchResponseReference response, Document document,
        IoSession session ) throws IOException
    {
        // Creating the Document
        Element documentRoot = document.getRootElement();
        // Creating the root element
        Element root = documentRoot.addElement( ProxyIO.SEARCH_RESPONSE_REFERENCE_TAG );

        //getting the MessageID
        root.addAttribute( ProxyIO.MESSAGE_ID_TAG, Integer.toString( response.getMessageId() ) );

        //Getting Referrals

        Element ReferralElement = root.addElement( ProxyIO.REFERRAL_TAG );
        Collection<String> ldapUrls = response.getReferral().getLdapUrls();
        for ( String url : ldapUrls )
        {
            Element LDAPUrlElement = ReferralElement.addElement( ProxyIO.LDAP_URL_TAG );
            LDAPUrlElement.setText( url );
        }

        writeToDisk( session, document );

    }


    /**
     * Writes DeleteResponse to the log file
     *
     * @param response InternalDeleteResponse to be written to the file
     * @param document The XML document for the response to be written to
     * @param session The session corresponding to this conversation
     * @throws IOException
     */
    public static void writeDeleteResponse( InternalDeleteResponse response, Document document, IoSession session )
        throws IOException
    {
        // Creating the Document
        Element documentRoot = document.getRootElement();
        // Creating the root element
        Element root = documentRoot.addElement( ProxyIO.DELETE_RESPONSE_TAG );

        //getting the MessageID
        root.addAttribute( ProxyIO.MESSAGE_ID_TAG, Integer.toString( response.getMessageId() ) );

        //Writing the LDAP result part
        writeLDAPResult( root, response.getLdapResult() );

        writeToDisk( session, document );

    }


    /**
     * Writes CompareResponse to the log file
     *
     * @param response InternalCompareResponse to be written to the file
     * @param document The XML document for the response to be written to
     * @param session The session corresponding to this conversation
     * @throws IOException
     */
    public static void writeCompareResponse( InternalCompareResponse response, Document document, IoSession session )
        throws IOException
    {
        // Creating the Document
        Element documentRoot = document.getRootElement();
        // Creating the root element
        Element root = documentRoot.addElement( ProxyIO.COMPARE_RESPONSE_TAG );

        //getting the MessageID
        root.addAttribute( ProxyIO.MESSAGE_ID_TAG, Integer.toString( response.getMessageId() ) );

        //Writing the LDAP result part
        writeLDAPResult( root, response.getLdapResult() );

        writeToDisk( session, document );

    }


    /**
     * Writes ModifyResponse to the log file
     *
     * @param response InternalModifyResponse to be written to the file
     * @param document The XML document for the response to be written to
     * @param session The session corresponding to this conversation
     * @throws IOException
     */
    public static void writeModifyResponse( InternalModifyResponse response, Document document, IoSession session )
        throws IOException
    {
        // Creating the Document
        Element documentRoot = document.getRootElement();
        // Creating the root element
        Element root = documentRoot.addElement( ProxyIO.MODIFY_RESPONSE_TAG );

        //getting the MessageID
        root.addAttribute( ProxyIO.MESSAGE_ID_TAG, Integer.toString( response.getMessageId() ) );

        //Writing the LDAP result part
        writeLDAPResult( root, response.getLdapResult() );

        writeToDisk( session, document );

    }


    /**
     * Writes ModifyDnResponse to the log file
     *
     * @param response InternalModifyDnResponse to be written to the file
     * @param document The XML document for the response to be written to
     * @param session The session corresponding to this conversation
     * @throws IOException
     */
    public static void writeModifyDnResponse( InternalModifyDnResponse response, Document document, IoSession session )
        throws IOException
    {
        // Creating the Document
        Element documentRoot = document.getRootElement();
        // Creating the root element
        Element root = documentRoot.addElement( ProxyIO.MODIFY_DN_RESPONSE_TAG );

        //getting the MessageID
        root.addAttribute( ProxyIO.MESSAGE_ID_TAG, Integer.toString( response.getMessageId() ) );

        //Writing the LDAP result part
        writeLDAPResult( root, response.getLdapResult() );

        writeToDisk( session, document );

    }


    /**
     * Writes ExtendedResponse to the log file
     *
     * @param response InternalExtendedResponse to be written to the file
     * @param document The XML document for the response to be written to
     * @param session The session corresponding to this conversation
     * @throws IOException
     */
    public static void writeExtendedResponse( InternalExtendedResponse response, Document document, IoSession session )
        throws IOException
    {
        // Creating the Document
        //Document document = DocumentHelper.createDocument();
        Element documentRoot = document.getRootElement();
        // Creating the root element
        Element root = documentRoot.addElement( ProxyIO.EXTENDED_RESPONSE_TAG );

        //getting the MessageID
        root.addAttribute( ProxyIO.MESSAGE_ID_TAG, Integer.toString( response.getMessageId() ) );

        //Getting Response Name
        Element responseNameElement = root.addElement( ProxyIO.RESPONSE_NAME_TAG );
        responseNameElement.setText( response.getResponseName() );

        //Getting Response
        Element responseElement = root.addElement( ProxyIO.RESPONSE_TAG );
        responseElement.setText( new String( response.getResponse() ) );

        //Writing the LDAP result part
        writeLDAPResult( root, response.getLdapResult() );

        writeToDisk( session, document );

    }


    /**
     * Parses the log file for extracting different type of LDAP messages
     *
     * @param document The XML document the messages should be read from
     * @throws IOException, LdapInvalidDnException
     */
    public static void parseLog( Document document ) throws IOException, LdapInvalidDnException
    {
        Element documentRoot = document.getRootElement();
        // iterate through child elements of root
        for ( Iterator<?> i = documentRoot.elementIterator(); i.hasNext(); )
        {
            Element element = ( Element ) i.next();
            if ( element.getName().equals( ABANDON_REQUEST_TAG ) )
            {
                InternalAbandonRequest msg = readAbondonRequest( element );
            }
            else if ( element.getName().equals( ADD_REQUEST_TAG ) )
            {
                InternalAddRequest msg = readAddRequest( element );
            }
            else if ( element.getName().equals( ADD_RESPONSE_TAG ) )
            {
                InternalAddResponse msg = readAddResponse( element );
            }
            else if ( element.getName().equals( BIND_REQUEST_TAG ) )
            {
                InternalBindRequest msg = readBindRequest( element );
            }
            else if ( element.getName().equals( BIND_RESPONSE_TAG ) )
            {
                InternalBindResponse msg = readBindResponse( element );
            }
            else if ( element.getName().equals( COMPARE_REQUEST_TAG ) )
            {
                InternalCompareRequest msg = readCompareRequest( element );
            }
            else if ( element.getName().equals( COMPARE_RESPONSE_TAG ) )
            {
                InternalCompareResponse msg = readCompareResponse( element );
            }
            else if ( element.getName().equals( DELETE_REQUEST_TAG ) )
            {
                InternalDeleteRequest msg = readDeleteRequest( element );
            }
            else if ( element.getName().equals( DELETE_RESPONSE_TAG ) )
            {
                InternalDeleteResponse msg = readDeleteResponse( element );
            }
            else if ( element.getName().equals( EXTENDED_REQUEST_TAG ) )
            {
                InternalExtendedRequest msg = readExtendedRequest( element );
            }
            else if ( element.getName().equals( EXTENDED_RESPONSE_TAG ) )
            {
                InternalExtendedResponse msg = readExtendedResponse( element );
            }
            else if ( element.getName().equals( MODIFY_DN_REQUEST_TAG ) )
            {
                InternalModifyDnRequest msg = readModifyDnRequest( element );
            }
            else if ( element.getName().equals( MODIFY_DN_RESPONSE_TAG ) )
            {
                InternalModifyDnResponse msg = readModifyDnResponse( element );
            }
            else if ( element.getName().equals( MODIFY_REQUEST_TAG ) )
            {
                InternalModifyRequest msg = readModifyRequest( element );
            }
            else if ( element.getName().equals( MODIFY_RESPONSE_TAG ) )
            {
                InternalModifyResponse msg = readModifyResponse( element );
            }
            else if ( element.getName().equals( SEARCH_REQUEST_TAG ) )
            {
                InternalSearchRequest msg = readSearchRequest( element );
            }
            else if ( element.getName().equals( SEARCH_RESPONSE_DONE_TAG ) )
            {
                InternalSearchResponseDone msg = readSearchResponseDone( element );
            }
            else if ( element.getName().equals( SEARCH_RESPONSE_ENTRY_TAG ) )
            {
                InternalSearchResponseEntry msg = readSearchResponseEntry( element );
            }
            else if ( element.getName().equals( SEARCH_RESPONSE_REFERENCE_TAG ) )
            {
                InternalSearchResponseReference msg = readSearchResponseReference( element );
            }
            else if ( element.getName().equals( UNBIND_REQUEST_TAG ) )
            {
                InternalUnbindRequest msg = readUnbindRequest( element );
            }
        }
    }


    /**
     * Reads ModifyDnRequest from a log file
     *
     * @param element XML element to be read from
     * @return InternalModifyDnRequest message 
     * @throws LdapInvalidDnException
     */
    private static InternalModifyDnRequest readModifyDnRequest( Element element ) throws LdapInvalidDnException
    {
        //Creating New Message with message ID
        InternalModifyDnRequest message = new ModifyDnRequestImpl( Integer.parseInt( element.valueOf( "@"
            + ProxyIO.MESSAGE_ID_TAG ) ) );

        message.setName( new DN( element.valueOf( "@" + ProxyIO.NAME_TAG ) ) );

        message.setNewRdn( new RDN( element.valueOf( "@" + ProxyIO.NEW_RDN_TAG ) ) );

        message.setDeleteOldRdn( Boolean.parseBoolean( element.valueOf( "@" + ProxyIO.DELETE_OLD_RDN_TAG ) ) );
        message.setNewSuperior( new DN( element.valueOf( "@" + ProxyIO.NEW_SUPERIOR_TAG ) ) );

        return message;
    }


    /**
     * Reads ModifyDnResponse from a log file
     *
     * @param element XML element to be read from
     * @return InternalModifyDnResponse message 
     * @throws LdapInvalidDnException
     */
    private static InternalModifyDnResponse readModifyDnResponse( Element element ) throws LdapInvalidDnException
    {
        //Creating New Message with message ID
        InternalModifyDnResponse message = new ModifyDnResponseImpl( Integer.parseInt( element.valueOf( "@"
            + ProxyIO.MESSAGE_ID_TAG ) ) );

        readLDAPResult( element, message.getLdapResult() );
        return message;
    }


    /**
     * Reads ModifyRequest from a log file
     *
     * @param element XML element to be read from
     * @return InternalModifyRequest message 
     * @throws LdapInvalidDnException
     */
    private static InternalModifyRequest readModifyRequest( Element element ) throws LdapInvalidDnException
    {
        //Creating New Message with message ID
        InternalModifyRequest message = new ModifyRequestImpl( Integer.parseInt( element.valueOf( "@"
            + ProxyIO.MESSAGE_ID_TAG ) ) );

        message.setName( new DN( element.valueOf( "@" + ProxyIO.NAME_TAG ) ) );
        //TODO add modification items
        //message.addModification( mod );
        return message;
    }


    /**
     * Reads ModifyResponse from a log file
     *
     * @param element XML element to be read from
     * @return InternalModifyResponse message 
     * @throws LdapInvalidDnException
     */
    private static InternalModifyResponse readModifyResponse( Element element ) throws LdapInvalidDnException
    {
        //Creating New Message with message ID
        InternalModifyResponse message = new ModifyResponseImpl( Integer.parseInt( element.valueOf( "@"
            + ProxyIO.MESSAGE_ID_TAG ) ) );

        readLDAPResult( element, message.getLdapResult() );
        return message;
    }


    /**
     * Reads Search Request from a log file
     *
     * @param element XML element to be read from
     * @return InternalSearchRequest message 
     * @throws LdapInvalidDnException
     */

    private static InternalSearchRequest readSearchRequest( Element element ) throws LdapInvalidDnException
    {
        //Creating New Message with message ID
        InternalSearchRequest message = new SearchRequestImpl( Integer.parseInt( element.valueOf( "@"
            + ProxyIO.MESSAGE_ID_TAG ) ) );

        message.setBase( new DN( element.valueOf( "@" + ProxyIO.BASE_DN_TAG ) ) );
        // TODO Set filter properly
        if ( element.valueOf( "@" + ProxyIO.SCOPE_TAG ) == "base object" )
        {
            message.setScope( SearchScope.OBJECT );
        }
        else if ( element.valueOf( "@" + ProxyIO.SCOPE_TAG ) == "single level" )
        {
            message.setScope( SearchScope.ONELEVEL );
        }
        else if ( element.valueOf( "@" + ProxyIO.SCOPE_TAG ) == "whole subtree" )
        {
            message.setScope( SearchScope.SUBTREE );
        }

        message.setTypesOnly( Boolean.parseBoolean( element.valueOf( "@" + ProxyIO.TYPES_ONLY_TAG ) ) );
        message.setSizeLimit( Long.parseLong( element.valueOf( "@" + ProxyIO.SIZE_LIMIT_TAG ) ) );
        message.setTimeLimit( Integer.parseInt( element.valueOf( "@" + ProxyIO.TIME_LIMIT_TAG ) ) );

        if ( element.valueOf( "@" + ProxyIO.ALIAS_DEREF_MODE_TAG ) == ProxyIO.NEVER_DEREF_ALIASES_CONST )
        {
            message.setDerefAliases( AliasDerefMode.NEVER_DEREF_ALIASES );
        }
        else if ( element.valueOf( "@" + ProxyIO.ALIAS_DEREF_MODE_TAG ) == ProxyIO.DEREF_IN_SEARCHING_CONST )
        {
            message.setDerefAliases( AliasDerefMode.DEREF_IN_SEARCHING );
        }
        else if ( element.valueOf( "@" + ProxyIO.ALIAS_DEREF_MODE_TAG ) == ProxyIO.DEREF_FINDING_BASE_OBJ_CONST )
        {
            message.setDerefAliases( AliasDerefMode.DEREF_FINDING_BASE_OBJ );
        }
        else if ( element.valueOf( "@" + ProxyIO.ALIAS_DEREF_MODE_TAG ) == ProxyIO.DEREF_ALWAYS_CONST )
        {
            message.setDerefAliases( AliasDerefMode.DEREF_ALWAYS );
        }
        Element attributesElement = element.element( ProxyIO.ATTRIBUTES_TAG );
        for ( Iterator<Element> i = attributesElement.elementIterator( ProxyIO.ATTRIBUTE_TAG ); i.hasNext(); )
        {
            Element attr = ( Element ) i.next();
            message.addAttribute( attr.valueOf( "@" + ProxyIO.NAME_TAG ) );
        }

        return message;
    }


    /**
     * Reads SearchResponsedone from a log file
     *
     * @param element XML element to be read from
     * @return InternalSearchResponseDone message 
     * @throws LdapInvalidDnException
     */
    private static InternalSearchResponseDone readSearchResponseDone( Element element ) throws LdapInvalidDnException
    {
        //Creating New Message with message ID
        InternalSearchResponseDone message = new SearchResponseDoneImpl( Integer.parseInt( element.valueOf( "@"
            + ProxyIO.MESSAGE_ID_TAG ) ) );

        readLDAPResult( element, message.getLdapResult() );
        return message;
    }


    /**
     * Reads SearchResponseEntry from a log file
     *
     * @param element XML element to be read from
     * @return InternalSearchResponseEntry message 
     * @throws LdapInvalidDnException
     */
    private static InternalSearchResponseEntry readSearchResponseEntry( Element element ) throws LdapInvalidDnException
    {
        //Creating New Message with message ID
        InternalSearchResponseEntry response = new SearchResponseEntryImpl( Integer.parseInt( element.valueOf( "@"
            + ProxyIO.MESSAGE_ID_TAG ) ) );

        response.setObjectName( new DN( element.valueOf( "@" + ProxyIO.OBJECT_NAME_TAG ) ) );

        /*for ( Iterator i = response.elementIterator( ProxyIO.ATTRIBUTE_TAG ); i.hasNext(); ) {
            Element attributeEle = (Element) i.next();
            for ( Iterator i = response.elementIterator( ProxyIO.ATTRIBUTE_TAG ); i.hasNext(); ) {
                Element attributeEle = (Element) i.next();
                // do something
            }
        }
        
        Entry attrs = new DefaultServerEntry();
        attrs.put( getEntry( "attr0" ) );

        EntryAttribute attr = new DefaultEntryAttribute( id );
        attr.add( "value0" );

        response.setEntry();*/

        // TODO Have to complete

        return response;
    }


    /**
     * Reads SearchResponseReference from a log file
     *
     * @param element XML element to be read from
     * @return InternalSearchResponseReference message 
     * @throws LdapInvalidDnException
     */
    private static InternalSearchResponseReference readSearchResponseReference( Element element )
    {
        InternalSearchResponseReference message = new SearchResponseReferenceImpl( Integer
            .parseInt( ProxyIO.MESSAGE_ID_TAG ) );
        Element ReferralElement = element.element( ProxyIO.REFERRAL_TAG );
        ReferralImpl ref = new ReferralImpl();
        for ( Iterator i = ReferralElement.elementIterator( ProxyIO.LDAP_URL_TAG ); i.hasNext(); )
        {
            Element url = ( Element ) i.next();
            ref.addLdapUrl( url.getTextTrim() );
        }

        message.setReferral( ref );
        return null;
    }


    /**
     * Reads Unbind request from a log file
     *
     * @param element XML element to be read from
     * @return InternalUnibindRequest message 
     * @throws LdapInvalidDnException
     */
    private static InternalUnbindRequest readUnbindRequest( Element element )
    {
        InternalUnbindRequest message = new UnbindRequestImpl( Integer.parseInt( ProxyIO.MESSAGE_ID_TAG ) );

        return message;
    }


    /**
     * Reads Extended Response from a log file
     *
     * @param element XML element to be read from
     * @return InternalExtendedResponse message 
     * @throws LdapInvalidDnException
     */

    private static InternalExtendedResponse readExtendedResponse( Element element ) throws LdapInvalidDnException
    {
        //Creating New Message with message ID
        InternalExtendedResponse message = new ExtendedResponseImpl( Integer.parseInt( element.valueOf( "@"
            + ProxyIO.MESSAGE_ID_TAG ) ) );

        message.setResponseName( element.elementText( ProxyIO.RESPONSE_NAME_TAG ) );
        message.setResponse( element.elementText( ProxyIO.RESPONSE_TAG ).getBytes() );
        //reading the LDAP result part

        readLDAPResult( element, message.getLdapResult() );

        return message;
    }


    /**
     * Reads Extended request from a log file
     *
     * @param element XML element to be read from
     * @return Internal Extended request message 
     * @throws LdapInvalidDnException
     */
    private static InternalExtendedRequest readExtendedRequest( Element element )
    {
        //Creating New Message with message ID
        InternalExtendedRequest message = new ExtendedRequestImpl( Integer.parseInt( element.valueOf( "@"
            + ProxyIO.MESSAGE_ID_TAG ) ) );
        //Setting oid
        message.setOid( element.elementText( ProxyIO.OID_TAG ) );

        //Setting payload
        message.setPayload( element.elementText( ProxyIO.PAYLOAD_TAG ).getBytes() );
        return message;
    }


    /**
     * Reads Delete Response from a log file
     *
     * @param element XML element to be read from
     * @return Internal Delete response message 
     * @throws LdapInvalidDnException
     */
    private static InternalDeleteResponse readDeleteResponse( Element element ) throws LdapInvalidDnException
    {
        //Creating New Message with message ID
        InternalDeleteResponse message = new DeleteResponseImpl( Integer.parseInt( element.valueOf( "@"
            + ProxyIO.MESSAGE_ID_TAG ) ) );

        readLDAPResult( element, message.getLdapResult() );
        return message;
    }


    /**
     * Reads Delete request from a log file
     *
     * @param element XML element to be read from
     * @return Internal Delete request message 
     * @throws LdapInvalidDnException
     */
    private static InternalDeleteRequest readDeleteRequest( Element element ) throws LdapInvalidDnException
    {
        InternalDeleteRequest message = new DeleteRequestImpl( Integer.parseInt( element.valueOf( "@"
            + ProxyIO.MESSAGE_ID_TAG ) ) );
        message.setName( new DN( element.valueOf( "@" + ProxyIO.NAME_TAG ) ) );

        return message;
    }


    /**
     * Reads compare response from a log file
     *
     * @param element XML element to be read from
     * @return InternalCompareResponse message 
     * @throws LdapInvalidDnException
     */
    private static InternalCompareResponse readCompareResponse( Element element ) throws LdapInvalidDnException
    {
        //Creating New Message with message ID
        InternalCompareResponse message = new CompareResponseImpl( Integer.parseInt( element.valueOf( "@"
            + ProxyIO.MESSAGE_ID_TAG ) ) );

        readLDAPResult( element, message.getLdapResult() );
        return message;
    }


    /**
     * Reads compare request from a log file
     *
     * @param element XML element to be read from
     * @return InternalCompareRequest message 
     * @throws LdapInvalidDnException
     */
    private static InternalCompareRequest readCompareRequest( Element element )
    {
        InternalCompareRequest message = new CompareRequestImpl( Integer.parseInt( element.valueOf( "@"
            + ProxyIO.MESSAGE_ID_TAG ) ) );
        //Getting the Assertion value
        Element assertionValueElement = element.element( ProxyIO.VALUE_TAG );
        // TODO Have to implement full assertian value part
        return message;
    }


    /**
     * Reads bind response from a log file
     *
     * @param element XML element to be read from
     * @return InternalBindResponse message 
     * @throws LdapInvalidDnException
     */
    private static InternalBindResponse readBindResponse( Element element ) throws LdapInvalidDnException
    {
        //Creating New Message with message ID
        InternalBindResponse message = new BindResponseImpl( Integer.parseInt( element.valueOf( "@"
            + ProxyIO.MESSAGE_ID_TAG ) ) );
        //Setting Server SASL credentials
        message.setServerSaslCreds( element.elementText( ProxyIO.SERVER_SASL_CREDS_TAG ).getBytes() );
        //reading the LDAP result part

        readLDAPResult( element, message.getLdapResult() );
        return message;
    }


    /**
     * Reads LDAPResult part of the message from a log file
     *
     * @param element XML element to be read from
     * @param ldapResult to be modified 
     * @throws LdapInvalidDnException
     */
    private static void readLDAPResult( Element element, InternalLdapResult ldapResult ) throws LdapInvalidDnException
    {
        Element LDAPResultElement = element.element( ProxyIO.LDAP_RESULT_TAG );
        //Getting the Result Code       
        ldapResult.setResultCode( ResultCodeEnum.getResultCode( Integer.parseInt( LDAPResultElement
            .elementText( ProxyIO.RESULT_CODE_TAG ) ) ) );

        //Getting the Matched Dn
        ldapResult.setMatchedDn( new DN( LDAPResultElement.elementText( ProxyIO.MATCHED_DN_TAG ) ) );

        //Getting Error Message
        ldapResult.setErrorMessage( LDAPResultElement.elementText( ProxyIO.ERROR_MESSAGE_TAG ) );

        InternalReferral ref = new ReferralImpl();
        Element ReferralElement = LDAPResultElement.element( ProxyIO.REFERRAL_TAG );

        for ( Iterator<Element> i = ReferralElement.elementIterator( ProxyIO.LDAP_URL_TAG ); i.hasNext(); )
        {
            Element url = ( Element ) i.next();
            ref.addLdapUrl( url.getTextTrim() );
        }

        ldapResult.setReferral( ref );
    }


    /**
     * Reads bind request from a log file
     *
     * @param element XML element to be read from
     * @return InternalBindRequest message 
     * @throws LdapInvalidDnException
     */
    private static InternalBindRequest readBindRequest( Element element ) throws LdapInvalidDnException
    {
        //Creating New Message with message ID
        InternalBindRequest message = new BindRequestImpl( Integer.parseInt( element.valueOf( "@"
            + ProxyIO.MESSAGE_ID_TAG ) ) );
        //Setting Version
        message.setVersion3( Boolean.parseBoolean( element.elementText( ProxyIO.VERSION_TAG ) ) );
        //Setting name
        message.setName( new DN( element.elementText( ProxyIO.NAME_TAG ) ) );

        //setting authentication
        Element authElement = element.element( ProxyIO.AUTHENTICATION_TAG );
        if ( authElement.valueOf( "@" + ProxyIO.TYPE_TAG ).equals( ProxyIO.TYPE_SIMPLE ) )
        {
            message.setSimple( true );
        }
        else
        {
            message.setSimple( false );
            message.setSaslMechanism( authElement.elementText( ProxyIO.MECHANISM_TAG ) );
        }
        //setting credentials
        message.setCredentials( authElement.elementText( ProxyIO.CREDENTIALS_TAG ).getBytes() );

        return message;
    }


    /**
     * Reads add response from a log file
     *
     * @param element XML element to be read from
     * @return InternalAddResponse message 
     * @throws LdapInvalidDnException
     */
    private static InternalAddResponse readAddResponse( Element element ) throws LdapInvalidDnException
    {
        InternalAddResponse message = new AddResponseImpl( Integer.parseInt( element.valueOf( "@"
            + ProxyIO.MESSAGE_ID_TAG ) ) );

        readLDAPResult( element, message.getLdapResult() );
        return message;
    }


    /**
     * Reads add request from a log file
     *
     * @param element XML element to be read from
     * @return InternalAddRequest message 
     * @throws LdapInvalidDnException
     */
    private static InternalAddRequest readAddRequest( Element element ) throws LdapInvalidDnException
    {
        InternalAddRequest message = new AddRequestImpl( Integer.parseInt( element.valueOf( "@"
            + ProxyIO.MESSAGE_ID_TAG ) ) );

        //Getting the entryDN  

        message.setEntryDn( new DN( element.valueOf( "@" + ProxyIO.ENTRY_DN_TAG ) ) );

        //TODO Getting the entry

        return message;
    }


    /**
     * Reads abandon request from a log file
     *
     * @param element XML element to be read from
     * @return InternalAbandonRequest message 
     * @throws LdapInvalidDnException
     */
    private static InternalAbandonRequest readAbondonRequest( Element element )
    {

        InternalAbandonRequest message = new AbandonRequestImpl( Integer.parseInt( element.valueOf( "@"
            + ProxyIO.MESSAGE_ID_TAG ) ) );
        //Getting the abandoned     
        message.setAbandoned( Integer.parseInt( element.elementText( ProxyIO.ABANDONED_TAG ) ) );

        return message;
    }


    /**
     * Reads abandon request from a log file
     *
     * @param session for the document is needed
     * @return The corresponding Document for the Session 
     * @throws DocumentException
     */
    public static Document getDocumentForSession( IoSession session ) throws DocumentException
    {

        File file = new File( session.getId() + "" );
        Document document;

        if ( !( file.exists() ) )
        {
            document = DocumentHelper.createDocument();
            document.addElement( "messageLog" );
            return document;
        }
        else
        {
            SAXReader reader = new SAXReader();
            document = reader.read( file );
            return document;
        }

    }

}
